home *** CD-ROM | disk | FTP | other *** search
/ QRZ! Ham Radio 8 / QRZ Ham Radio Callsign Database - Volume 8.iso / mac / files / t_sys5 / unixcpio.gz / unixnet.cpio / slfp.c < prev    next >
C/C++ Source or Header  |  1994-07-11  |  12KB  |  532 lines

  1. /* Send and receive IP datagrams on serial lines. Compatible with SL/FP
  2.  * as used with the Merit Network and MIT.
  3.  */
  4. #include "config.h"
  5. #ifdef SLFP
  6.  
  7. #include <stdio.h>
  8. #include "global.h"
  9. #include "mbuf.h"
  10. #include "iface.h"
  11. #include "timer.h"
  12. #include "ip.h"
  13. #include "slfp.h"
  14.  
  15. #ifdef UNIX    /* BSD or SYS5 */
  16. #include "unix.h"
  17. #endif
  18.  
  19. #include "asy.h"
  20. #ifdef MSDOS
  21. #include "8250.h"
  22. #endif
  23. #include "trace.h"
  24.  
  25. int asy_ioctl();
  26. int slfp_send();
  27. int doslfp();
  28. int asy_output();
  29.  
  30. /* SL/FP level control structure */
  31. struct slfp slfp[ASY_MAX];
  32. char slfp_ack[ACK_LEN] = { SLFP_ACK } ;
  33. char slfp_req[REQ_LEN] = { SLFP_REQ } ;
  34. char ip_hdr[HDR_LEN] = { 2, 1, 0, 0 } ;    /* IP Packet Header */
  35. char ar_hdr[HDR_LEN] = { 2, 3, 0, 0 } ;    /* "Addr Req" Packet Header */
  36. struct interface asy_interface =    /* Fake interface for "dump" proc */
  37.     { NULLIF, "asy" } ;        /* Name of "asy" interface */
  38.  
  39. /* Routine to Initialize the Async line for SL/FP processing.
  40.  * Mostly involves requesting the IP Address for this host.
  41.  */
  42. int
  43. slfp_init(interface,modem_cmd)
  44. struct interface *interface ;
  45. char *modem_cmd ;        /* optional command to Modem */
  46. {
  47.     register struct slfp *sp;
  48.     register struct timer *ar ;
  49.     char *modem_line ;
  50.     int i ;
  51.  
  52.     sp = &slfp[interface->dev];
  53.     ar = &sp->ar_timer ;
  54.  
  55.     slfp[interface->dev].req_pending = 0 ;
  56.  
  57.     /* If a Modem Command is present, send it and wait for Connection */
  58.     if (modem_cmd != NULLCHAR) {
  59.     char c; c='\r';
  60.     modem_line = (char *)malloc(strlen(modem_cmd)+2) ;
  61.     if (modem_line == NULLCHAR)
  62.         return -1 ;
  63.     strcpy(modem_line, modem_cmd);
  64.     strcat(modem_line, "\r") ;
  65.     asy_output(interface->dev,&c,1);    /* Wake up modem */
  66.     set_timer(ar,500);
  67.     start_timer(ar);
  68.     while(ar->state == TIMER_RUN)
  69.         keep_things_going();
  70.     asy_output(interface->dev,modem_line,strlen(modem_line));
  71.     free(modem_line);
  72.     set_timer(ar, 30000) ;    /* Wait up to 30 seconds for Connection */
  73.     start_timer(ar);
  74.     } else
  75.     set_timer(ar, 500) ;    /* Wait half a second before sending REQs */
  76.  
  77.     if (ip_addr == 0) {        /* Ask network for my IP address... */
  78.     sp->ar_pending = 1 ;
  79.  
  80.     /* Request an Address up to 4 times (every 10 seconds) before giving up */
  81.     for (i=0; i<4; i++) {
  82.         start_timer(ar) ;
  83.         while (sp->ar_pending && (ar->state == TIMER_RUN)) {
  84.         keep_things_going() ;    /* Can't return until timeout or addr */
  85.         if(kbread()==(-2))        /* Hit the Escape key */
  86.             return(-1);
  87.         }
  88.         if (!sp->ar_pending) {
  89.         return 0 ;
  90.         }
  91.         slfp_send(NULLBUF, interface, 0L, 0, 0, 0, 0) ;
  92.         set_timer(ar, 10000) ;    /* Wait up to 10 seconds for IP Addr */
  93.     }
  94.  
  95.     sp->ar_pending = 0 ;
  96.     return -1 ;
  97.     } else
  98.     return 0;
  99. }
  100.  
  101. /* Send routine for point-to-point slfp
  102.  * This is a trivial function since slfp_encode adds the link-level header
  103.  */
  104. int
  105. slfp_send(bp,interface,gateway,precedence,delay,throughput,reliability)
  106. struct mbuf *bp;        /* Buffer to send */
  107. struct interface *interface;    /* Pointer to interface control block */
  108. int32 gateway;
  109. char precedence;
  110. char delay;
  111. char throughput;
  112. char reliability;
  113. {
  114.     if(interface == NULLIF){
  115.         free_p(bp);
  116.         return;
  117.     }
  118.     dump(interface,IF_TRACE_OUT,TRACE_IP,bp);
  119.     (*interface->raw)(interface,bp);
  120. }
  121. /* Send a raw slfp frame -- also trivial */
  122. slfp_raw(interface,bp)
  123. struct interface *interface;
  124. struct mbuf *bp;
  125. {
  126.     /* Make "asy" interface a shadow of the SLFP interface */
  127.     asy_interface.trace = interface->trace ;
  128.  
  129.     /* Queue a frame on the slfp output queue and start transmitter */
  130.     slfpq(interface->dev,bp);
  131. }
  132. /* Encode a raw packet in slfp framing, put on link output queue, and kick
  133.  * transmitter
  134.  */
  135. static
  136. slfpq(dev,bp)
  137. int16 dev;        /* Serial line number */
  138. struct mbuf *bp;    /* Buffer to be sent */
  139. {
  140.     register struct slfp *sp;
  141.     struct mbuf *slfp_encode();
  142.  
  143.     if((bp = slfp_encode(dev,bp)) == NULLBUF)
  144.         return;    
  145.  
  146.     sp = &slfp[dev];
  147.     enqueue(&sp->sndq,bp);
  148.     dump(&asy_interface,IF_TRACE_OUT,TRACE_SLFP,bp);
  149.     sp->sndcnt++;
  150.     if(sp->tbp == NULLBUF)
  151.         slfp_asy_start(dev);
  152. }
  153.  
  154. /* Handle REQ-ACK Timer expiration
  155.  */
  156. void
  157. slfp_req_notify(dev)
  158. int16 dev;
  159. {
  160.     register struct slfp *sp;
  161.     register struct timer *rt ;        /* Timer for REQ-ACK negotiation */
  162.     struct mbuf *bp ;
  163.  
  164.     sp = &slfp[dev];
  165.     rt = &(sp->req_timer) ;
  166.     if (sp->reqcnt++ >= 10) {
  167.     sp->tbp = NULLBUF ;
  168.     sp->req_pending = 0 ;
  169.     bp = dequeue(&sp->sndq);
  170.     sp->sndcnt--;
  171.     free_p(bp) ;
  172.     }
  173.     else {
  174.     set_timer(rt,2000) ;        /* 2-Second Timeout for ACK */
  175.     start_timer(rt) ;
  176.     asy_output(dev, slfp_req, REQ_LEN) ;
  177.     }
  178. }
  179.  
  180. /* Start output, if possible, on asynch device dev */
  181. static
  182. slfp_asy_start(dev)
  183. int16 dev;
  184. {
  185.     register struct slfp *sp;
  186.     register struct timer *rt ;    /* Timer for REQ-ACK negotiation */
  187.     struct mbuf *bp ;
  188.  
  189.     if(!stxrdy(dev))
  190.         return;        /* Transmitter not ready */
  191.  
  192.     sp = &slfp[dev];
  193.     bp = sp->tbp ;
  194.     if(bp != NULLBUF){
  195.         /* transmission just completed */
  196.         free_p(bp) ;
  197.         sp->tbp = NULLBUF;
  198.     }
  199.     if(sp->sndq == NULLBUF)
  200.         return;    /* No work */
  201.  
  202.     rt = &(sp->req_timer) ;
  203.     if (sp->req_pending)
  204.         return ;
  205.     sp->reqcnt = 0 ;
  206.     sp->req_pending = 1 ;
  207.     rt->func = slfp_req_notify ;
  208.     rt->arg = (char *)dev ;
  209.     set_timer(rt,2000) ;        /* 2-Second Timeout for ACK */
  210.     start_timer(rt) ;
  211.     asy_output(dev, slfp_req, REQ_LEN) ;
  212. }
  213. /* Encode a packet in SL/FP format */
  214. static
  215. struct mbuf *
  216. slfp_encode(dev,bp)
  217. int16 dev;        /* Serial line number */
  218. struct mbuf *bp;
  219. {
  220.     struct mbuf *lbp;    /* Mbuf containing line-ready packet */
  221.     register char *cp;
  222.     char c;
  223.  
  224.     /* Allocate output mbuf that's twice as long as the packet.
  225.      * This is a worst-case guess (consider a packet full of SLFP_ENDs!)
  226.      */
  227.     lbp = alloc_mbuf(HDR_LEN + 2*len_mbuf(bp) + 2);
  228.     if(lbp == NULLBUF){
  229.         /* No space; drop */
  230.         free_p(bp);
  231.         return NULLBUF;
  232.     }
  233.     cp = lbp->data;
  234.  
  235.     /* Prefix packet with the Correct Link-Level Header */
  236.     if (slfp[dev].ar_pending)
  237.         memcpy(cp, ar_hdr, HDR_LEN) ;
  238.     else
  239.         memcpy(cp, ip_hdr, HDR_LEN) ;
  240.     cp += HDR_LEN ;
  241.  
  242.     /* Copy input to output, escaping special characters */
  243.     while(pullup(&bp,&c,1) == 1){
  244.         switch(c & 0xff){
  245.         case SLFP_ESC:
  246.             *cp++ = SLFP_ESC;
  247.             *cp++ = SLFP_ESC - SLFP_ESC;
  248.             break;
  249.         case SLFP_END:
  250.             *cp++ = SLFP_ESC;
  251.             *cp++ = SLFP_END - SLFP_ESC;
  252.             break;
  253.         case SLFP_ACK:
  254.             *cp++ = SLFP_ESC;
  255.             *cp++ = SLFP_ACK - SLFP_ESC;
  256.             break;
  257.         case SLFP_REQ:
  258.             *cp++ = SLFP_ESC;
  259.             *cp++ = SLFP_REQ - SLFP_ESC;
  260.             break;
  261.         default:
  262.             *cp++ = c;
  263.         }
  264.     }
  265.     *cp++ = SLFP_END;
  266.     lbp->cnt = cp - lbp->data;
  267.     return lbp;
  268. }
  269.  
  270. #ifdef    MSDOS
  271. /* Invoked when SLFP_REQ is received during xmit of outgoing packet.
  272.  * This allows immediate reception of packet from SCP, rather than
  273.  * forcing it to buffer it until we finish sending the outgoing packet
  274.  */
  275. static
  276. unsigned
  277. slfp_urgent(dev)
  278. int16 dev;    /* SL/FP unit number */
  279. {
  280.     register struct dma *dp ;
  281.  
  282.     dp = &asy[dev].dma ;
  283.     if (dp->last_octet == SLFP_ESC)
  284.     return 256 ;
  285.     else {
  286.     asy[dev].urgent = NULLCHAR ;
  287.     return SLFP_ACK ;
  288.     }
  289. }
  290. #endif
  291.  
  292. void
  293. hndl_rcvd_req(dev, sp)
  294. int16 dev;    /* SL/FP unit number */
  295. register struct slfp *sp;
  296. {
  297.     char i_state ;
  298.  
  299.     if (sp->reqd) { /* REQ before rcv'g END of last Packet! */
  300.     sp->missed_ends++ ;
  301.     free_p(sp->rbp);    /* throw away current packet */
  302.     sp->rbp = NULLBUF;
  303.     sp->rcnt = 0;
  304.     }
  305.  
  306.     sp->reqd = 1 ;
  307.     i_state = disable() ;
  308. #ifdef    MSDOS
  309.     if (asy[dev].dma.flags)
  310.     asy[dev].urgent = slfp_urgent ;
  311.     else
  312. #endif
  313.     asy_output(dev, slfp_ack, ACK_LEN) ;
  314.     restore(i_state) ;
  315. }
  316.  
  317. void
  318. hndl_rcvd_ack(dev, sp)
  319. int16 dev;    /* SL/FP unit number */
  320. register struct slfp *sp;
  321. {
  322.     char i_state ;
  323.  
  324.     i_state = disable() ;
  325.     if (sp->req_pending == 0) {
  326.         sp->false_acks++ ;
  327.         restore(i_state) ;
  328.         return ;
  329.     }
  330.     sp->req_pending = 0 ;
  331.     stop_timer(&(sp->req_timer)) ;
  332.     restore(i_state) ;
  333.     sp->tbp = dequeue(&sp->sndq);
  334.     sp->sndcnt--;
  335.     asy_output(dev,sp->tbp->data,sp->tbp->cnt);
  336. }
  337.  
  338. /* Process incoming bytes in SL/FP format
  339.  * When a buffer is complete, return it; otherwise NULLBUF
  340.  */
  341. static
  342. struct mbuf *
  343. slfp_decode(dev,c)
  344. int16 dev;    /* SL/FP unit number */
  345. char c;        /* Incoming character */
  346. {
  347.     struct mbuf *bp;
  348.     register struct slfp *sp;
  349.     unsigned char uc ;
  350.  
  351.     sp = &slfp[dev];
  352.  
  353.     uc = c & 0xff;
  354.     if (uc == SLFP_REQ) {
  355.         hndl_rcvd_req(dev, sp) ;
  356.         return NULLBUF ;
  357.     }
  358.     if (uc == SLFP_ACK) {
  359.         hndl_rcvd_ack(dev, sp) ;
  360.         return NULLBUF ;
  361.     }
  362.     if (sp->reqd == 0) {
  363.         return NULLBUF ;
  364.     }
  365.  
  366.     switch(uc){
  367.     case SLFP_END:
  368.         sp->reqd = 0 ;
  369.         /* Kick upstairs */
  370.         bp = sp->rbp;
  371.         sp->rbp = NULLBUF;
  372.         sp->rcnt = 0;
  373.         return bp;
  374.         break ;
  375.  
  376.     case SLFP_ESC:
  377.         sp->escaped = 1;
  378.         return NULLBUF;
  379.     }
  380.     if(sp->escaped){
  381.         sp->escaped = 0;
  382.         uc += SLFP_ESC;
  383.         switch(uc){
  384.         case SLFP_ESC:
  385.         case SLFP_REQ:
  386.         case SLFP_ACK:
  387.         case SLFP_END:
  388.             break;
  389.         default:
  390.             uc -= SLFP_ESC;
  391.             sp->bad_esc++;
  392.             sp->errors++;
  393.         }
  394.     }
  395.     /* We reach here with a character for the buffer;
  396.      * make sure there's space for it
  397.      */
  398.     if(sp->rbp == NULLBUF){
  399.         /* Allocate first mbuf for new packet */
  400.         if((sp->rbp1 = sp->rbp = alloc_mbuf(SLFP_ALLOC)) == NULLBUF)
  401.             return NULLBUF; /* No memory, drop */
  402.         sp->rcp = sp->rbp->data;
  403.     } else if(sp->rbp1->cnt == SLFP_ALLOC){
  404.         /* Current mbuf is full; link in another */
  405.         if((sp->rbp1->next = alloc_mbuf(SLFP_ALLOC)) == NULLBUF){
  406.             /* No memory, drop whole thing */
  407.             free_p(sp->rbp);
  408.             sp->rbp = NULLBUF;
  409.             sp->rcnt = 0;
  410.             return NULLBUF;
  411.         }
  412.         sp->rbp1 = sp->rbp1->next;
  413.         sp->rcp = sp->rbp1->data;
  414.     }
  415.     /* Store the character, increment fragment and total
  416.      * byte counts
  417.      */
  418.     *sp->rcp++ = uc;
  419.     sp->rbp1->cnt++;
  420.     sp->rcnt++;
  421.     return NULLBUF;
  422. }
  423. /* Process SL/FP line I/O */
  424. int
  425. doslfp(interface)
  426. struct interface *interface;
  427. {
  428.     char c;
  429.     struct mbuf *bp, *cp=NULLBUF;
  430.     int16 dev;
  431.     int16 asy_recv();
  432.  
  433.     dev = interface->dev;
  434.     /* Process any pending input */
  435.     while(asy_recv(dev,&c,1) != 0) {
  436.         if((bp = slfp_decode(dev,c)) != NULLBUF) {
  437.             (*slfp[dev].recv)(interface,bp);
  438.         }
  439.     }
  440.     if (cp != NULLBUF)
  441.         (*slfp[dev].recv)(interface,cp);
  442.     
  443.     /* Kick the transmitter if it's idle */
  444.     if(stxrdy(dev))
  445.         slfp_asy_start(dev);
  446. }
  447.  
  448. /* Handle Address Reply packets
  449.  */
  450. void
  451. addr_reply(dev,bp)
  452. int16 dev;
  453. struct mbuf *bp;
  454. {
  455.     if (len_mbuf(bp) != 4) { /* Invalid Address Response */
  456.     free_p(bp) ;
  457.     return ;
  458.     }
  459.     if (!slfp[dev].ar_pending) {
  460.     free_p(bp) ;
  461.     return ;
  462.     }
  463.     stop_timer(&slfp[dev].ar_timer) ;
  464.     slfp[dev].ar_pending = 0 ;
  465.     ip_addr = (unsigned char)(*bp->data++) ;
  466.     ip_addr <<= 8 ;
  467.     ip_addr |= (unsigned char)(*bp->data++) ;
  468.     ip_addr <<= 8 ;
  469.     ip_addr |= (unsigned char)(*bp->data++) ;
  470.     ip_addr <<= 8 ;
  471.     ip_addr |= (unsigned char)(*bp->data++) ;
  472.     free_p(bp) ;
  473. }
  474.  
  475. /* Unwrap incoming SL/FP packets -- use link level header to determine
  476.  * how to handle packet
  477.  */
  478. slfp_recv(interface,bp)
  479. struct interface *interface;
  480. struct mbuf *bp;
  481. {
  482.     void ip_route();
  483.  
  484.     dump(interface,IF_TRACE_IN,TRACE_SLFP,bp);
  485.     if (len_mbuf(bp) < HDR_LEN) {
  486.         free_p(bp) ;
  487.         return ;
  488.     }
  489.     if (memcmp(ip_hdr, bp->data, HDR_LEN) == 0) {
  490.         bp->data += HDR_LEN ;
  491.         bp->cnt -= HDR_LEN ;
  492.         dump(interface,IF_TRACE_IN,TRACE_IP,bp);
  493.         ip_route(bp,0); /* By def'n, all inbound packets are addr'd to us */
  494.     }
  495.     else if (memcmp(ar_hdr, bp->data, HDR_LEN) == 0) {
  496.         bp->data += HDR_LEN ;
  497.         bp->cnt -= HDR_LEN ;
  498.         dump(interface,IF_TRACE_IN,TRACE_IP,bp);
  499.         addr_reply(interface->dev,bp);
  500.     } else {
  501.         dump(interface,IF_TRACE_IN,TRACE_IP,bp);
  502.         free_p(bp) ;
  503.     }
  504. }
  505.  
  506. int
  507. slfp_dump(bpp, check)
  508. struct mbuf **bpp;
  509. int check ;
  510. {
  511.     if(bpp == NULLBUFP || *bpp == NULLBUF)
  512.         return 0;    
  513.  
  514.     printf("SLFP: ");
  515.     /* Sneak peek at IP header and find length */
  516.     if (len_mbuf(*bpp) < HDR_LEN) {
  517.         printf("packet too short!\n");
  518.         return 0;
  519.     }
  520.  
  521.     if (memcmp(ip_hdr, (*bpp)->data, HDR_LEN) == 0)
  522.         printf("IP Packet\n") ;
  523.     else if (memcmp(ar_hdr, (*bpp)->data, HDR_LEN) == 0)
  524.         printf("Addr Req Packet\n") ;
  525.     else
  526.         printf("bad header\n") ;
  527.  
  528.     return 0 ;
  529. }
  530.  
  531. #endif /* SLFP */
  532.